package com.wxh.bomb.netty.echo.server;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;

/**
 * Echo服务器
 *
 * @author wxh
 * @date：2017.10.19
 */
public class EchoServer {
    private final int port1;
    private final int port2;

    public EchoServer(int port1, int port2) {
        this.port1 = port1;
        this.port2 = port2;
    }

    /**
     * 服务启动
     */
    private void start() throws InterruptedException {
        //1 第一个线程组 是用于接收Client端连接的
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        //2 第二个线程组 是用于实际的业务处理操作的
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            //3 创建一个辅助类Bootstrap，就是对我们的Server进行一系列的配置
            ServerBootstrap b = new ServerBootstrap();
            // 把俩个工作线程组加入进来
            b.group(bossGroup, workerGroup)
                    // 我要指定使用NioServerSocketChannel这种类型的通道
                    .channel(NioServerSocketChannel.class)         // 指定NIO的模式
                    .option(ChannelOption.SO_BACKLOG, 1024)        // 设置tcp缓冲区
                    .option(ChannelOption.SO_SNDBUF, 32 * 1024)    // 设置发送缓冲大小
                    .option(ChannelOption.SO_RCVBUF, 32 * 1024)    // 这是接收缓冲大小
                    .option(ChannelOption.SO_KEEPALIVE, true)      // 保持连接
                    // 一定要使用 childHandler 去绑定具体的 事件处理器
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel sc) throws Exception {
                            //设置特殊分隔符,使用分隔符拆包
                            // 或者使用FixedLengthFrameDecoder
                            ByteBuf buf = Unpooled.copiedBuffer("$_".getBytes());
                            sc.pipeline().addLast(new DelimiterBasedFrameDecoder(1024, buf));
                            //设置字符串形式的解码
                            sc.pipeline().addLast(new StringDecoder());
                            sc.pipeline().addLast(new EchoServerHandler());
                        }
                    });

            // 异步绑定服务器，实现绑定多个端口
            ChannelFuture future1 = b.bind(port1).sync();
            ChannelFuture future2 = b.bind(port2).sync();

            System.out.println("=======================================================");
            System.out.println(EchoServer.class.getSimpleName() + " started and listen on " + future1.channel().localAddress());
            System.out.println(EchoServer.class.getSimpleName() + " started and listen on " + future2.channel().localAddress());
            System.out.println("=======================================================");

            // 异步关闭
            future1.channel().closeFuture().sync();
            future2.channel().closeFuture().sync();
        } finally {
            bossGroup.shutdownGracefully().sync();
            workerGroup.shutdownGracefully().sync();
        }
    }

    public static void main(String[] args) {
        try {
            new EchoServer(8080, 8081).start();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}
